#pragma once
#include <typeinfo.h>
#include <list>
#include <string>
#include <set>
#include <bitset>
#include "utils.h"
#include<iostream>
typedef unsigned int UINT;
typedef signed char Jbyte;
typedef Jbyte UBYTE;
typedef short JShort;



struct NodeData
{
	JShort totalByte;
	UBYTE code;
	UBYTE dataOffect;
	UBYTE *data;
	void createData(UBYTE code,UBYTE *&data ,UBYTE dataLength,UBYTE dataOffect)
	{
		this->code = code;
		this->data = data;
		this->dataOffect = dataOffect;
		this->totalByte = sizeof(JShort)+sizeof(UBYTE)+sizeof(UBYTE)*dataLength+sizeof(UBYTE);
	}
	std::string toString()
	{
		JShort dataLength = totalByte-sizeof(JShort)-sizeof(UBYTE)-sizeof(UBYTE);
		std::string rst;
		UBYTE of = dataOffect;
		for(JShort i = 0;i<dataLength;++i)
		{
			append(rst,data[i],of);
			of=0;
		}


		//JShort start = 0;
		//if(dataOffect)
		//{
		//	append(rst,data[0],dataOffect);
		//	start+=1;
		//}
		//while(start<dataLength)
		//{
		//	append(rst,data[start],0);
		//	start+=1;
		//}
		return rst;
	}
	void append(std::string &result,UBYTE bit,UBYTE offect)
	{
		UBYTE num_bit = 8-offect;
		while(num_bit>0)
		{
			UBYTE  n = bit>>(--num_bit);
			result+=utl::to_string((n&1));
		}
	}
	friend std::ostream& operator<<(std::ostream& os, NodeData &data) 
	{
		std::string result = data.toString();
		os<<result;
		return os;
	}

	~NodeData()
	{
		if(data!=NULL)
		{
			delete[] data;
		}
	}

};
struct NodeFlag
{
	bool isParent;
	UINT N;
	NodeFlag(bool isP,UINT num):isParent(isP),N(num){}

	virtual std::ostream& print(std::ostream &os)
	{
		os<<isParent<<":"<<N;
		return os;
	}

	virtual ~NodeFlag()
	{

	}
};

struct ChildNode:public NodeFlag
{
	UBYTE c;
	NodeData *data;
public:
	ChildNode(UBYTE c,UINT n):NodeFlag(false,n),c(c){}

	void writeCode(std::string& cd,int len)
	{
		data = new NodeData();
		int dataLength;
		int firstBitStart = len%8;

		UBYTE *aData;
		UBYTE offect;
		if(firstBitStart==0)
		{
			dataLength = len/8;
			aData = new UBYTE[dataLength];
			offect = 0;
			for(int i = 0;i<dataLength;++i)
			{
				std::bitset<8> bit(cd,i*8,8);
				aData[i] = (UBYTE)bit.to_ulong();
			}
		}
		else
		{
			dataLength = len/8+1;
			aData = new UBYTE[dataLength];
			offect = 8-firstBitStart;

			std::bitset<8> bit(cd,0,firstBitStart);
			aData[0] = (UBYTE) bit.to_ulong();

			//std::cout<<aData[0]<<std::endl;
			for(int i=1;i<dataLength;++i)
			{
				std::bitset<8> bit(cd,(i-1)*8+firstBitStart,8);
				aData[i] = (UBYTE)bit.to_ulong();
			}
		}
		data->createData(c,aData,dataLength,offect);

	}
	std::ostream& print (std::ostream &os) override
	{
		os<<"child:("<<(int)c<<")"<<":"<<NodeFlag::N;
		return os;
	}



	virtual ~ ChildNode(){
		delete[] data;
	}

};
struct ParentNode:public NodeFlag
{
	NodeFlag *left,*right;
	std::ostream& print(std::ostream &os) override
	{
		os<<"child:"<<":"<<N;
		return os;
	}
public:
	ParentNode( NodeFlag *left, NodeFlag *right):NodeFlag(true,left->N+right->N),left(left),right(right){}

};
struct RootNode
{
	NodeFlag *root;

	~RootNode()
	{
		deleteNode(root);
	}

	void deleteNode(NodeFlag *node)
	{
		if((typeid(*node)==typeid(ParentNode)))
		{
			ParentNode *p = (ParentNode*)node;
			deleteNode(p->left);
			deleteNode(p->right);
			delete p;
		}
		else
		{
			delete node;
		}
	}
};






RootNode* buildTree2(UBYTE* &,int size);
std::string transCoding(RootNode*root,UBYTE* &source,int Ssize,int offect);
void nnnn_get();
